package com.baize.filedowndemo

//import com.liulishuo.filedownloader.FileDownloadListener
//import com.liulishuo.filedownloader.FileDownloader
import android.annotation.SuppressLint
import android.app.Activity
import android.content.*
import android.database.Cursor
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.*
import android.provider.MediaStore
import android.util.Log
import android.view.KeyEvent
import android.view.LayoutInflater
import android.webkit.MimeTypeMap
import android.widget.Button
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import androidx.work.*
import com.baize.filedowndemo.conversationFile.ProgressInterceptor
import com.baize.filedowndemo.conversationFile.ProgressListener
import com.baize.filedowndemo.utils.*
import com.baize.filedowndemo.utils.FileUri.dumpMetaData
import com.baize.filedowndemo.workmanager.TestWorker
import com.liulishuo.okdownload.DownloadListener
import com.liulishuo.okdownload.DownloadTask
import com.liulishuo.okdownload.core.breakpoint.BreakpointInfo
import com.liulishuo.okdownload.core.cause.EndCause
import com.liulishuo.okdownload.core.cause.ResumeFailedCause
import okhttp3.*
import okhttp3.logging.HttpLoggingInterceptor
import java.io.*
import java.net.HttpURLConnection
import java.net.URL
import java.util.concurrent.TimeUnit
import kotlin.concurrent.thread
import androidx.documentfile.provider.DocumentFile


class MainActivity : AppCompatActivity() {
  val PICK_FILE = 1
  val BAIDU_HTML = "http://www.baidu.com"
  val FILE_DOWNLOAD_URL =
    "https://oss-doufan-story.oss-cn-hangzhou.aliyuncs.com/upload/cdn/app-debug.apk"
  val IMAGE_URL = "https://www.docufty.com/uploads/tupian/url%20(49).jpg"

  val LOCAL_IMAGE = "/storage/emulated/0/Pictures/2021.11.23 at 16_18_48 GMT+08_00.jpg"

  //  🍎文件名：: test.apk
  //  🍑Uri转换为Path=/storage/emulated/0/Android/data/com.baize.filedowndemo/files/Documents/Download/test.apk
  //  文件大小：40752246
  val LOCAL_FILE =
    "/storage/emulated/0/Android/data/com.baize.filedowndemo/files/Documents/Download/test.apk";

  lateinit var pick_file: Button
  lateinit var download_file: Button
  lateinit var download_use_okhttp: Button
  lateinit var progressBar: ProgressBar
  lateinit var iv_image: ImageView
  lateinit var check_local_file: Button

  val handler: Handler by lazy {
    Handler(Looper.getMainLooper())
  }

  val sharePreferences: SharedPreferences by lazy {
    application.getSharedPreferences("file_history", Context.MODE_PRIVATE)
  }

  val okHttpClient =
    OkHttpClient.Builder().readTimeout(30, TimeUnit.SECONDS).writeTimeout(30, TimeUnit.SECONDS)
      .addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
      .addInterceptor(ProgressInterceptor()).build()

  @RequiresApi(Build.VERSION_CODES.O)
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    pick_file = findViewById<Button>(R.id.pick_file)
    pick_file.setOnClickListener { pickFile() }
    download_file = findViewById<Button>(R.id.download_file)
    download_file.setOnClickListener {
      downloadFile(FILE_DOWNLOAD_URL, "guolindemo.apk")
    }
    download_use_okhttp = findViewById<Button>(R.id.download_use_okhttp)
    download_use_okhttp.setOnClickListener {
      downloadUseOkhttp(FILE_DOWNLOAD_URL)
    }
    progressBar = findViewById(R.id.progressbar)
    iv_image = findViewById(R.id.iv_image)
    val bitmap = BitmapFactory.decodeFile(LOCAL_IMAGE)
    if (bitmap != null) {
      iv_image.setImageBitmap(bitmap)
    }
    findViewById<Button>(R.id.check_local_file).setOnClickListener {
      Log.i("baize_selector", "$LOCAL_FILE is exits : ${FileUtil.fileIsExists(LOCAL_FILE)}")
    }
    findViewById<Button>(R.id.request_permiss).setOnClickListener {
      FileUri.jumpManageAppAllFilesPermissionSetting(this, true)
    }
    findViewById<Button>(R.id.down_use_libiary).setOnClickListener { //使用库下载
      val file = File(
        getCacheDir(), "test.apk"
      ) //      if (file.exists()) { //        file.delete() //      }
      Log.i(
        "baize_", "onCreate: ${file.absolutePath}"
      )
      val task: DownloadTask =
        DownloadTask.Builder(FILE_DOWNLOAD_URL, getCacheDir()).setFilename("test.apk")
          .setMinIntervalMillisCallbackProcess(30) // 下载进度回调的间隔时间（毫秒）
          .setPassIfAlreadyCompleted(false) // 任务过去已完成是否要重新下载
          .setPriority(10).build()

      task.enqueue(object : DownloadListener {
        override fun taskStart(task: DownloadTask) {
          Log.i("baize_", "taskStart: ")
        }

        override fun connectTrialStart(
          task: DownloadTask, requestHeaderFields: MutableMap<String, MutableList<String>>
        ) {
          Log.i("baize_", "connectTrialStart: ")
        }

        override fun connectTrialEnd(
          task: DownloadTask,
          responseCode: Int,
          responseHeaderFields: MutableMap<String, MutableList<String>>
        ) {
          Log.i("baize_", "connectTrialEnd: ")
        }

        override fun downloadFromBeginning(
          task: DownloadTask, info: BreakpointInfo, cause: ResumeFailedCause
        ) {
          Log.i("baize_", "downloadFromBeginning: ")
        }

        override fun downloadFromBreakpoint(task: DownloadTask, info: BreakpointInfo) {
          Log.i("baize_", "downloadFromBreakpoint: ")
        }

        override fun connectStart(
          task: DownloadTask,
          blockIndex: Int,
          requestHeaderFields: MutableMap<String, MutableList<String>>
        ) {
          Log.i("baize_", "connectStart: ")
        }

        override fun connectEnd(
          task: DownloadTask,
          blockIndex: Int,
          responseCode: Int,
          responseHeaderFields: MutableMap<String, MutableList<String>>
        ) {
          Log.i("baize_", "connectEnd: ")
        }

        override fun fetchStart(task: DownloadTask, blockIndex: Int, contentLength: Long) {
          Log.i("baize_", "fetchStart: ")
        }

        override fun fetchProgress(task: DownloadTask, blockIndex: Int, increaseBytes: Long) {
          Log.i("baize_", "fetchProgress: $blockIndex $increaseBytes")
        }

        override fun fetchEnd(task: DownloadTask, blockIndex: Int, contentLength: Long) {
          Log.i("baize_", "fetchEnd: ")
        }

        override fun taskEnd(task: DownloadTask, cause: EndCause, realCause: java.lang.Exception?) {
          Log.i("baize_", "taskEnd: ")
        }
      })
    }
    findViewById<Button>(R.id.start_work_manager).setOnClickListener { //约束条件
      val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.UNMETERED)
        .setRequiresCharging(true).build()

      //setExpedited() 来声明工作器应使用加急作业
      val uploadWorkRequest: OneTimeWorkRequest =
        OneTimeWorkRequestBuilder<TestWorker>() //        .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)  //如果配额允许，它将立即开始在后台运行（DROP_WORK_REQUEST，这会在配额不足时导致请求取消）
          //        .setConstraints(constraints)
          //        .setBackoffCriteria(
          //          BackoffPolicy.LINEAR,
          //          OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
          //          TimeUnit.MILLISECONDS
          //        )
          .setInputData(workDataOf("IMAGE_URI" to BAIDU_HTML)).addTag(BAIDU_HTML) //标记工作
          .build()

      //      WorkManager.getInstance(this).enqueue(uploadWorkRequest)
      WorkManager.getInstance(this)
        .enqueueUniqueWork(BAIDU_HTML, ExistingWorkPolicy.KEEP, uploadWorkRequest)   //用于一次性工作 唯一工作

      WorkManager.getInstance(this).getWorkInfoByIdLiveData(uploadWorkRequest.id)
        .observe(this, Observer { info ->
          Log.i("baize", "onCreate: progress...${info.progress.getInt("Progress", 0)}")
          if (info != null && info.state.isFinished) {
            val myResult = info.outputData.getString("KEY_RESULT")
            Log.i(
              "baize_",
              "${info.id} 任务执行结果!${myResult} 是否成功：${info.state == WorkInfo.State.SUCCEEDED}"
            ) // ... do something with the result ...
          }
        })
    }

    //    val workList = WorkManager.getInstance(this).getWorkInfosByTag(BAIDU_HTML)
    //    val work: MutableList<WorkInfo> = workList.get()
    //    Log.i(
    //      "baize_",
    //      "onCreate: ${work.size} 个工作正在执行！${
    //        (if (work.size > 0) work.map { it.id to it.state.isFinished }.toString() else "null id")
    //      }"
    //    )

    // by tag
    //    WorkManager.getInstance(this).cancelAllWorkByTag(BAIDU_HTML)
    findViewById<Button>(R.id.down_use_mutable_libiary).setOnClickListener {
      startActivity(Intent(this, MulitDownActivity::class.java))
    }

    findViewById<Button>(R.id.check_file_exist).setOnClickListener { //      pickFilePath?.let {
      //        val file = File(it)
      //        val exist = file.exists()
      //        Log.i("baize_", "path：${file?.absolutePath} 是否存在: $exist")
      //        return@setOnClickListener
      //      }
      pickFileUri?.let { //方式一：
        //        val sourceFile = DocumentFile.fromSingleUri(this, pickFileUri!!)
        //        val exist = sourceFile!!.exists()

        //方式二：
        val exist = checkUri(it)
        Log.i("baize_", "Uri：${pickFileUri?.toString()} 是否存在: $exist")
      }


      //      val fileName = "/test1.apk"
      //      val downloadPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
      //      val uri = Uri.parse("${downloadPath}$fileName")
      //      val exist = FileUri.checkUri(uri)
      //      val file = File(downloadPath, fileName)
      //      val exist = file.exists()
      //      MediaStore.getDocumentUri(this,)

      //      val file: File? = File("/storage/emulated/0/Android/data/com.dodolive.app/files/Documents/Music/sound_2.wav")
      //      val exist = file?.exists() ?: ""

      //      Log.i("baize_", "path：${file?.absolutePath} 是否存在: $exist")
    }

    findViewById<Button>(R.id.open_file).setOnClickListener { //      pickFilePath?.let {
      //        val file = File(it)
      //        val originalUri = FileUri.getUriByFile(file,false)
      //        Log.i("baize_", "打开的文件Uri: $originalUri 路径：${file.absolutePath}")
      //        FileOpener.openUrl(this, originalUri!!)
      //        return@setOnClickListener
      //      }

      pickFileUri?.let {
        FileOpener.openUrl(this, pickFileUri!!)
      }

      //      val fileName = "/test1.apk"
      //      val fileName = "/新建文本文档.txt"
      //      val downloadPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
      //      val file = File(downloadPath, fileName)

      //      val originalUri = FileUri.getUriByFile(file,false)
      //      Log.i("baize_", "文件Uri: $originalUri 路径：${file.absolutePath}")
      //      FileOpener.openUrl(this, originalUri!!)
    }
    val cacheUri = sharePreferences.getString("uri", null)
    if (cacheUri != null) {
      Log.i("baize_", "onCreate: 恢复Uri:${cacheUri.toString()}")
      pickFileUri = Uri.parse(cacheUri)
    }
    findViewById<Button>(R.id.copy_file).setOnClickListener {
      val sourceFile = File(cacheDir, "test1.apk")
      FileUri.writeFileToLocal(sourceFile)
    }
    findViewById<Button>(R.id.btn_notification).setOnClickListener {
      startActivity(Intent(this@MainActivity, NotificationActivity::class.java))
    }
  }

  val flags111: Int =
    Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION

  //选择文件
  fun pickFile() { //ACTION_GET_CONTENT, ACTION_OPEN_DOCUMENT 效果相同, Android Q 上使用 `ACTION_GET_CONTENT` 会出现:SecurityException
    val intent =
      Intent(Intent.ACTION_OPEN_DOCUMENT).apply { //      flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
        flags = flags111
        addCategory(Intent.CATEGORY_OPENABLE)
        type = "*/*"
      }
    startActivityForResult(intent, PICK_FILE)
  }

  @SuppressLint("WrongConstant")
  override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    when (requestCode) {
      PICK_FILE -> {
        if (resultCode == Activity.RESULT_OK && data != null) {
          val uri = data.data
          contentResolver.takePersistableUriPermission(uri!!, flags111)
          pickFileUri = uri //保存Uri
          sharePreferences.edit().putString("uri", uri.toString()).apply()
          Log.i("baize_", "onActivityResult: 保存Uri:${uri.toString()}")
          if (uri != null) { //文件流上传
            //            val intputStream = contentResolver.openInputStream(uri)
            //            this.mimeType = FileMimeType.getMimeType(u)
            //            this.fileType = findFileType(u)

            showUriInfo(uri)

            //            val filePath: File? = FileHelper.uriToFileQ(this, uri)
            //            Log.i("baize", "onActivityResult: select File path: " + filePath?.absolutePath)
            //
            //            filePath?.let {
            //              val startTime = System.currentTimeMillis()
            //              val md5 = Md5Utils.gen(filePath)
            //              val suffix = FileUtil.getVideoFilePostfix(filePath.name);
            //              Log.i("baize_", "md5：$md5 耗时：${System.currentTimeMillis() - startTime} suffix：$suffix")
            //              Toast.makeText(this,"md5：$md5 耗时：${System.currentTimeMillis() - startTime} suffix：$suffix",Toast.LENGTH_SHORT).show()
            //            }

            dumpMetaData(uri = uri) { name: String?, _: String? ->
              pickFilePath = FileUri.getPathByUri(uri)
              if (name?.endsWith(".apk") == true) {
                val filePath = FileUri.getPathByUri(uri)
                if (filePath == null) {
                  Toast.makeText(this, "无法拿到真实Path！！！", Toast.LENGTH_SHORT).show()
                } else {
                  installApk(filePath)
                }
              } else {
                FileOpener.openUrl(this, uri)
              }
            }
          }
        }
      }
    }
  }

  var pickFilePath: String? = null
  var pickFileUri: Uri? = null

  //下载文件
  fun downloadFile(fileUrl: String, fileName: String) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
      Toast.makeText(
        this, "You must use device running Android 10 or higher", Toast.LENGTH_SHORT
      ).show()
      return
    }
    thread {
      try {
        val url = URL(fileUrl)
        val connection = url.openConnection() as HttpURLConnection
        connection.requestMethod = "GET"
        connection.connectTimeout = 8000
        connection.readTimeout = 8000
        val inputStream = connection.inputStream
        val bis = BufferedInputStream(inputStream)
        val values = ContentValues()
        values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
        values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
        val uri = contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values)
        if (uri != null) {
          val outputStream = contentResolver.openOutputStream(uri)
          if (outputStream != null) {
            val bos = BufferedOutputStream(outputStream)
            val buffer = ByteArray(1024)
            var bytes = bis.read(buffer)
            while (bytes >= 0) {
              Log.i("baize_", "downloadFile...")
              bos.write(buffer, 0, bytes)
              bos.flush()
              bytes = bis.read(buffer)
            }
            bos.close()
          }
        } else {
          Log.i("baize_", "uri = null!!!")
        }
        bis.close()
        Log.i("baize_", "下载完成! ${uri.toString()}")
        Toast.makeText(this, "下载完成！", Toast.LENGTH_SHORT).show()
      } catch (e: Exception) {
        e.printStackTrace()
      }
    }
  }

  fun downloadUseOkhttp(downloadUrl: String) {
    ProgressInterceptor.addListener(downloadUrl, object : ProgressListener {
      override fun onProgress(progress: Int) {
        runOnUiThread {
          progressBar.progress = progress
        }
      }
    })

    val request = Request.Builder().url(downloadUrl).build()

    okHttpClient.newCall(request).enqueue(object : Callback {
      override fun onFailure(call: Call, e: IOException) {
        Log.i("baize", "onFailure: ${e.message}")
        ProgressInterceptor.removeListener(downloadUrl)
      }

      override fun onResponse(call: Call, response: Response) {
        response.body?.byteStream()?.let { inputStream ->
          val bis = BufferedInputStream(inputStream)
          writeFileToLocal(bis)
        }
        Log.i("baize", "onResponse: ${response.code}")
        ProgressInterceptor.removeListener(downloadUrl)
      }
    })
  }

  fun writeFileToLocal(bis: BufferedInputStream) { //高版本适配：>= 29
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
      val startWrite = System.currentTimeMillis()
      val values = ContentValues()
      values.put(MediaStore.MediaColumns.DISPLAY_NAME, "test.apk")
      values.put(MediaStore.MediaColumns.AUTHOR, "md5")
      values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
      val uri = contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values)
      if (uri != null) {
        val outputStream = contentResolver.openOutputStream(uri)
        if (outputStream != null) {
          val bos = BufferedOutputStream(outputStream)
          val buffer = ByteArray(1024)
          var bytes = bis.read(buffer)
          while (bytes >= 0) {
            bos.write(buffer, 0, bytes)
            bos.flush()
            bytes = bis.read(buffer)
          }
          bos.close()
          runOnUiThread {
            Log.i("baize", "write done! 写入本地耗时：${System.currentTimeMillis() - startWrite}")
            Toast.makeText(this@MainActivity, "下载完成！", Toast.LENGTH_SHORT).show()
            showUriInfo(uri)
          }
        }
      }
    } else {
      Log.e("baize", "writeFileToLocal: 版本过低，请用其他下载方式!")
    }
  }

  fun downloadInWorkManager() {

  }

  /**
   * 打印文件信息
   */
  fun showUriInfo(uri: Uri) {
    val info = "🍑Uri转换为Path=${FileUri.getPathByUri(uri)}\n" + "文件大小：${
      FileUri.getFileSize(
        this, uri
      )
    }\n" + "md5：${
      Md5Utils.gen(
        this, uri
      )
    }\n" + "\uD83C\uDF48Path转换为Uri(FileProvider)=${FileUri.getUriByPath(FileUri.getPathByUri(uri))}"
    dumpMetaData(uri = uri) { name: String?, _: String? ->
      val text = """
                    | ------------------
                    | 🍎文件名：: $name
                    | $info
                    | ------------------${"\n\n\n"}""".trimMargin()
      Log.i("baize_selector", text)
    }
    val fileType = MimeTypeMap.getSingleton().getExtensionFromMimeType(contentResolver.getType(uri))
    Log.i("baize", "onActivityResult: select File type: $fileType")
  }

  /**
   * 安装apk
   */
  fun installApk(filePath: String) {
    val intent = Intent(Intent.ACTION_VIEW)
    intent.addCategory(Intent.CATEGORY_DEFAULT)
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
    val type = "application/vnd.android.package-archive"
    val uri: Uri?
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
      uri = FileUri.getUriByPath(filePath)
      intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    } else {
      uri = FileUri.getOriginalUri(filePath)
    }

    intent.setDataAndType(uri, type)
    startActivity(intent)
  }

  val QUERY_URI = MediaStore.Files.getContentUri("external")

  //  fun getRealPathAndroid_Q(uri: Uri): String? {
  //    App.getApplication().contentResolver.query(uri ?: return null, projection, selection, selectionArgs, null)?.use { c: Cursor ->
  //      if (c.moveToFirst()) {
  //        val columnIndex = c.getColumnIndex(column)
  //        return c.getString(columnIndex)
  //      }
  //    }
  //
  //    val QUERY_URI = MediaStore.Files.getContentUri("external")
  //    val data:Cursor = App.getApplication().getContentResolver().query(QUERY_URI, PROJECTION, getSelection(), getSelectionArgs(), ORDER_BY);
  //
  //
  //    MediaStore.Files.FileColumns._ID
  //    return QUERY_URI.buildUpon().appendPath(ValueOf.toString(id)).build().toString();
  //  }

  fun checkUri(uri: Uri?): Boolean {
    if (uri == null) return false
    val resolver = App.getApplication().contentResolver

    //1. Check Uri
    var cursor: Cursor? = null
    val isUriExist: Boolean = try {
      cursor = resolver.query(
        uri, null, null, null, null
      ) //cursor null: content Uri was invalid or some other error occurred
      //cursor.moveToFirst() false: Uri was ok but no entry found.
      (cursor != null && cursor.moveToFirst())
    } catch (t: Throwable) {
      Log.e("baize_", "1.Check Uri Error: ${t.message}")
      false
    } finally {
      try {
        cursor?.close()
      } catch (t: Throwable) {
      }
    }

    //2. Check File Exist
    //如果系统 db 存有 Uri 相关记录, 但是文件失效或者损坏 (If the system db has Uri related records, but the file is invalid or damaged)
    var ins: InputStream? = null
    val isFileExist: Boolean = try {
      ins = resolver.openInputStream(uri) // file exists
      true
    } catch (t: Throwable) { // File was not found eg: open failed: ENOENT (No such file or directory)
      Log.e("baize_", "2. Check File Exist Error: ${t.message}")
      false
    } finally {
      try {
        ins?.close()
      } catch (t: Throwable) {
      }
    }
    return isUriExist && isFileExist
  }
}